iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 24
0
Modern Web

資料視覺化!D3入門到實戰系列 第 24

Day24 實戰!Github Heat Map 產生器_接上open api

  • 分享至 

  • xImage
  •  

與前一個專案相同,大家應該都已經把layout大致刻好了,如果沒有也沒關係,可以使用我這個commit的程式碼:
https://github.com/yuanchen1103/2020ironman-github-contributions/commit/f44e65beba1195e15d3ea471fd7e3628d08b86fa


我們今天要使用的api文件在這裡:https://github.com/sallar/github-contributions-api
一般如果我們想要拿github的資料需要透過官方的api( https://developer.github.com/v3/ ),仔細研讀過後發現,若是要拿我們這次要使用的資料,可能需要申請一些權限,也要打好幾隻api才能整理出來,而我找到的這個人他已經幫我們整理好了,所以我們就直接拿來使用。這個api使用非常簡單:

GET https://github-contributions-api.now.sh/v1/GITHUB_USERNAME

我們可以拿自己的帳號來試打看看回傳的資料結構:

{
    years: [
        {
            year: '2019',
            total: 922,
            ...
        },
        ...
    ],
    contributions: [
        {
            date: '2019-12-31',
            count: 0,
            ...
        },
        ...
    ]
}

接著我們就可以使用前端來打api,在按下按鈕的時候會觸發一個getData的function,並把使用者輸入的帳號加到網址中

const [input, setInput] = useState(''); // user input
const [data, setData] = useState(null); // response
const [isLoading, setIsLoading] = useState();

const getData = useCallback(() => {
    if (!input.length) return; //沒有輸入的時候return
    setIsLoading(true); //開始loading
    axios
      .get(`https://github-contributions-api.now.sh/v1/${input}`)
      .then((res) => {
        setIsLoading(false); //停止loading
        setData(res.data); //把資料存起來
      })
      .catch((err) => {
        setIsLoading(false);
        setData(null);
        console.error(err);
      });
}, [input]);

知道了資料結構以後,我們就可以開始思考要怎麽裝進去我們的熱力圖裡面,因為我們一張熱力圖最多就是裝一年份的資料,且我們拿到的資料,都一定會有完整一年份的,因此我們就根據年來分組就可以了。

為了保持App.js的乾淨,我新建了一份js檔案來放跟算資料有關的function,這個資料我希望能是一個以年份為key的物件,值是那一年的陣列資料。

export const groupDataByYear = (data) => {
  const arr = data.contributions;
  const result = {};
  for (let i = 0; i < arr.length; i += 1) {
    const year = moment(arr[i].date).format('YYYY');
    if (!result[year]) {
      result[year] = [];
    }
    result[year].push({
      value: arr[i].count || 0,
      weekNum:
        momentObj.weekYear() === Number(year)
          ? momentObj.week()
          : momentObj.week() + moment(`${year}-01-01`).weeksInYear(),
      day: momentObj.day(),
      date: momentObj.format('YYYY-MM-DD'),
      weekYear: momentObj.weekYear()
    });
  }
  return result;
}

App.js中引進這個計算的函式,並產生各自的熱力圖:

const renderHeatMap = useCallback(() => {
    const groupData = groupDataByYear(data);
    return Object.keys(groupData)
      .sort()
      .reverse() //照倒反的年份順序排
      .map((year) => (
        <div className="heatmap-wrapper" key={year}>
          <HeatMapWidget
            title={`${year} ${!!data.years.find((e) => e.year === year) &&
              data.years.find((e) => e.year === year).total} contributions`} //圖表title
            chartData={groupData[year]}
          />
        </div>
      ));
}, [data]);

這樣一來我們就能夠產生基本的熱力圖囉~為了加強使用者效果,我們可以加上一些loading動畫與error catch,並在找不到資料時給一些提示。

今天的東西有點多,詳細可以看commit:
https://github.com/yuanchen1103/2020ironman-github-contributions/commit/8aa1143b4fe037c2d3917e588b044de168d0ccf3


上一篇
Day23 實戰!Github Heat Map 產生器_加上hover資料提示
下一篇
Day25 實戰!Github Heat Map 產生器_製作顏色選擇器
系列文
資料視覺化!D3入門到實戰30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言